#include "openmove_Prefix.h"
#include "SceneBase.h"
#include "OgreEngine.h"
#include "ExampleFrameListener.h"
#include "SkeletalAnimationFrameListener.h"
#include "OgreExternalTextureSourceManager.h"
#include "OgreExternalTextureSource.h"
#include "SceneCubenu.h"

#define TRANSITION_START 90.0f
#define TRANSITION_DURATION 7.0f

CSceneCubenu :: CSceneCubenu(COgreEngine &Creator, const String & Name, const int pos) : CSceneBase(Creator, Name, pos), m_Deform(false), m_curDeform(Vector4(1, 1, 0, 0))
{
}

CSceneCubenu :: ~CSceneCubenu(void)
{
}

void CSceneCubenu :: Create(TCreatorEntities const &CreatorEntities, TCreatorNodes const &CreatorNodes, TCreatorLights const &CreatorLights, ENetConfig IsClient, Vector3 &CameraStartPos)
{
	CSceneBase::Create(CreatorEntities, CreatorNodes, CreatorLights, IsClient, CameraStartPos);

	//m_pCurrentCamera->setPosition(-223.012f, 84.969f, -40.148f);
	//m_pCurrentCamera->rotate(Vector3(0, 1, 0), Radian(-1.979f));
	//m_OgreEngine.m_pViewPort->setBackgroundColour(ColourValue(0.0f, 0.0f, 0.0f, 1.0f));
	//m_OgreEngine.m_pCurrentSceneManager->setSkyBox(true, "SkyBox/Mountains");

	SProjectorFrustum decalFrustum = CreateProjector("PeauProjectorNode", /*Vector3(74.869, 382.656, -32.213), */
		Vector3(0, 382, 0),
		/*(Quaternion(Degree(-82.2), Vector3::UNIT_X) **/
		(Quaternion(Degree(-90), Vector3::UNIT_X) *
		Quaternion(Degree(0), Vector3::UNIT_Y) *
		Quaternion(Degree(0), Vector3::UNIT_Z)) * -Vector3::UNIT_Z);

	//decalFrustum.m_Decal->setFOVy(Radian(Math::PI/1.2));
	decalFrustum.m_Decal->setFOVy(Radian(Math::PI/2));
	decalFrustum.m_Decal->setAspectRatio(1.0);

	MaterialPtr mat;
	Pass *pass;
	
	std::vector<String> materials;
	materials.push_back("peau-decors/lambert2");
	materials.push_back("peau-decors_ana/peau_Ana4");
	materials.push_back("peau-decors_ana/lambert2");
	materials.push_back("peau-decors_nco/NCO_peau2");
	materials.push_back("peau-decors_nco/lambert3");

	for (std::vector<String>::iterator it = materials.begin(); it != materials.end(); ++it)
	{
		mat = (MaterialPtr)MaterialManager::getSingleton().getByName((*it));
		pass = mat->getTechnique(0)->getPass(0);
		TextureUnitState *texState;

		texState = pass->createTextureUnitState("peau_nu_video");
		texState->setProjectiveTexturing(true, decalFrustum.m_Decal);
		texState->setTextureAddressingMode(TextureUnitState::TAM_WRAP);
		texState->setTextureFiltering(TFO_ANISOTROPIC);
		texState->setColourOperationEx(LBX_MODULATE, LBS_TEXTURE, LBS_CURRENT);
		texState->setTextureBorderColour(ColourValue(1.0f, 1.0f, 1.0f, 1.0f));
	}

	materials.clear();
	materials.push_back("peau-decors_ana/peau_Ana1");
	materials.push_back("peau-decors_ana/peau_Ana");
	materials.push_back("peau-decors_nco/NCO_peau1");
	materials.push_back("peau-decors_nco/NCO_peau");

	for (std::vector<String>::iterator it = materials.begin(); it != materials.end(); ++it)
	{
		mat = (MaterialPtr)MaterialManager::getSingleton().getByName((*it));
		pass = mat->getTechnique(0)->getPass(0);
		TextureUnitState *texState;

		String const texName = pass->getTextureUnitState(0)->getTextureName();

		pass->removeAllTextureUnitStates();
		texState = pass->createTextureUnitState(texName);
		texState->setTextureCoordSet(0);

		texState = pass->createTextureUnitState("peau_nu_video");
		texState->setTextureCoordSet(1);
		texState->setProjectiveTexturing(true, decalFrustum.m_Decal);
		texState->setTextureAddressingMode(TextureUnitState::TAM_WRAP);
		texState->setTextureFiltering(TFO_ANISOTROPIC);
		texState->setColourOperationEx(LBX_MODULATE, LBS_TEXTURE, LBS_CURRENT);
		texState->setTextureBorderColour(ColourValue(1.0f, 1.0f, 1.0f, 1.0f));

		GpuProgramParametersSharedPtr vertexParams = mat->getTechnique(0)->getPass(0)->getVertexProgramParameters();
		vertexParams->setConstant(12, decalFrustum.m_Decal->getProjectionMatrix());
		vertexParams->setConstant(16, decalFrustum.m_Decal->getViewMatrix());

		GpuProgramParametersSharedPtr fragmentParams = mat->getTechnique(0)->getPass(0)->getFragmentProgramParameters();
		fragmentParams->setConstant(6, true);
	}
	/*
	{
		mat = (MaterialPtr)MaterialManager::getSingleton().getByName("peau-decors/lambert2");
		pass = mat->getTechnique(0)->getPass(0);
		TextureUnitState *texState;

		pass->removeAllTextureUnitStates();
		texState = pass->createTextureUnitState("scenoMap512.jpg");
		texState->setTextureCoordSet(0);

		texState = pass->createTextureUnitState("peau_nu2_video");
		texState->setTextureCoordSet(1);
		texState->setProjectiveTexturing(true, decalFrustum.m_Decal);
		texState->setTextureAddressingMode(TextureUnitState::TAM_WRAP);
		texState->setTextureFiltering(TFO_ANISOTROPIC);
		texState->setColourOperationEx(LBX_MODULATE, LBS_TEXTURE, LBS_CURRENT);
		texState->setTextureBorderColour(ColourValue(1.0f, 1.0f, 1.0f, 1.0f));

		GpuProgramParametersSharedPtr params = mat->getTechnique(0)->getPass(0)->getVertexProgramParameters();
		params->setConstant(12, decalFrustum.m_Decal->getProjectionMatrix() * decalFrustum.m_Decal->getViewMatrix());
	}
	*/

	m_Compositors.push_back("Glass");
}

void CSceneCubenu :: Attach(void)
{
	CSceneBase::Attach();

	m_Deform = false;
	m_curDeform = Vector4(1, 1, 0, 0);
}

void CSceneCubenu :: Detach(void)
{
	CSceneBase::Detach();
}

bool CSceneCubenu :: frameStarted(FrameEvent const &evt)
{
	CSceneBase::frameStarted(evt);

	Light *light = findLight(String("Peau-spotlight3"));
	if (NULL != light)
	{
		Entity *entity = findEntity(String("peau-joint-spot1"));
		if (entity->hasSkeleton())
		{
			Bone *bone = entity->getSkeleton()->getBone(0);
			light->setPosition(bone->getWorldPosition());
			//Vector3 direction = ((Quaternion(Degree(97.8), Vector3::UNIT_X) *
			//	Quaternion(Degree(84.8), Vector3::UNIT_Y) *
			//	Quaternion(Degree(0), Vector3::UNIT_Z)) * bone->getOrientation()) * Vector3::UNIT_Z;
			Vector3 direction = bone->getOrientation() * -Vector3::UNIT_Z;
			light->setDirection(direction);

			m_OgreEngine.setDebugText("direction: " + StringConverter::toString(direction));
		}
	}

	if (m_pCameraFrameListener->mInputDevice->isKeyDown(KC_Z) && m_pCameraFrameListener->mTimeUntilNextToggle <= 0)
	{
		fakeAddEvent(SOpenMoveDisplayPacket::e_PEE_StartWave, 3);
		m_pCameraFrameListener->mTimeUntilNextToggle = 1.0f;
	}
	if (m_pCameraFrameListener->mInputDevice->isKeyDown(KC_X) && m_pCameraFrameListener->mTimeUntilNextToggle <= 0)
	{
		fakeAddEvent(SOpenMoveDisplayPacket::e_PEE_StopWave, 3);
		m_pCameraFrameListener->mTimeUntilNextToggle = 1.0f;
	}

	if (m_Deform)
	{
		CompositorManager::getSingleton().setCompositorEnabled(m_OgreEngine.m_pViewPort, "Glass", true);
		m_curDeform.x += 0.1;
		m_curDeform.x = std::min(m_curDeform.x, 3.0f);
		if (m_curDeform.x >= 1 && 0)
		{
			m_curDeform.z = fmod(m_Timer.getSeconds(), 1);
		}
	}
	else
	{
		m_curDeform.x -= 0.1;
		m_curDeform.x = std::max(m_curDeform.x, 0.0f);
		if (0 == m_curDeform.x)
		{
			CompositorManager::getSingleton().setCompositorEnabled(m_OgreEngine.m_pViewPort, "Glass", false);
		}
	}

	m_OgreEngine.setDebugText("deformVal: " + StringConverter::toString(Vector3(m_curDeform.x,m_curDeform.y,m_curDeform.z)));

	return (true);
}

void CSceneCubenu :: processEvents(void)
{
	CSceneBase::processEvents();

	for (TEvents::iterator It = m_Events.begin(); It != m_Events.end(); ++It)
	{
		switch (It->m_Packet.eventid)
		{
			case SOpenMoveDisplayPacket::e_PEE_StartWave:
			{
				m_Deform = true;
				break;
			}
			case SOpenMoveDisplayPacket::e_PEE_StopWave:
			{
				m_Deform = false;
				break;
			}
		}
	}
}

void CSceneCubenu :: notifyMaterialSetup(uint32 pass_id, MaterialPtr &mat)
{
	CSceneBase::notifyMaterialSetup(pass_id, mat);

	if (mat->getNumTechniques() > 0 && mat->getTechnique(0)->getNumPasses() > 0)
	{
		if (pass_id == 0 && mat->getTechnique(0)->getPass(0)->getName() == "GlassPass")
		{
			Pass *pass = mat->getTechnique(0)->getPass(0);
			if (NULL != pass)
			{
				m_fpParams = pass->getFragmentProgramParameters();
			}
		}
	}
}

void CSceneCubenu :: notifyMaterialRender(uint32 pass_id, MaterialPtr &material)
{
	CSceneBase::notifyMaterialRender(pass_id, material);

	m_fpParams->setNamedConstant("value", m_curDeform);
}
